package com.szh.gulimall.auth.controller;

import com.alibaba.fastjson.TypeReference;
import com.szh.common.constant.AuthServerConstant;
import com.szh.common.constant.GulimallCodeEnum;
import com.szh.common.utils.R;
import com.szh.common.vo.MemberResponseVo;
import com.szh.gulimall.auth.feign.MemberFeignService;
import com.szh.gulimall.auth.feign.ThirdPartyFeignService;
import com.szh.gulimall.auth.vo.UserLoginVo;
import com.szh.gulimall.auth.vo.UserRegisterVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 普通登录
 *
 * @author: SongZiHao
 * @date: 2023/1/5
 */
@Controller
public class LoginController {

    @Autowired
    private ThirdPartyFeignService thirdPartyFeignService;

    @Autowired
    private MemberFeignService memberFeignService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 详情参考WebConfig这个类，仅仅是对接收到的请求做页面跳转功能
     */
//    @GetMapping(value = "/login.html")
//    public String loginPage() {
//        return "login";
//    }
//
//    @GetMapping(value = "/reg.html")
//    public String regPage() {
//        return "reg";
//    }

    /**
     * 调用第三方服务：阿里云短信验证码服务
     *
     * @param mobile 手机号
     * @return R.ok()
     */
    @ResponseBody
    @GetMapping("/sms/sendCode")
    public R sendSmsCode(@RequestParam("mobile") String mobile) {
        //调用短信验证码服务之前，先看一下Redis中有没有该手机号对应的验证码
        String redisCode = redisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + mobile);
        if (!StringUtils.isEmpty(redisCode)) {
            //按照_分割成两部分，后半部分就是验证码存入Redis时附带的系统时间
            long time = Long.parseLong(redisCode.split("_")[1]);
            //如果当前系统时间减去之前存入Redis验证码的系统时间小于60s，则不能再次发送短信验证码
            //也即防止同一个手机号在60s内再次发送验证码
            if (System.currentTimeMillis() - time < 60000) {
                return R.error(GulimallCodeEnum.SMS_CODE_EXCEPTION.getCode(), GulimallCodeEnum.SMS_CODE_EXCEPTION.getMsg());
            }
        }
        Random random = new Random();
        StringBuilder res = new StringBuilder();
        for (int i = 0; i < 6; i++) {
            res.append(random.nextInt(10));
        }
        String code = res.toString();
        res.append("_").append(System.currentTimeMillis());
        String timeCode = res.toString();
        //将验证码按照key为mobile手机号、value为验证码+系统时间的格式存入Redis，过期时间为5分钟
        redisTemplate.opsForValue().set(AuthServerConstant.SMS_CODE_CACHE_PREFIX + mobile,
                timeCode, 5, TimeUnit.MINUTES);
        thirdPartyFeignService.sendSmsCode(mobile, code);
        return R.ok();
    }

    /**
     * 用户注册
     * RedirectAttributes模拟重定向携带数据，利用session原理，将数据放在session中
     * 但是只要跳到下一个页面取出这些数据之后，session里面的数据就会删掉
     */
    @PostMapping(value = "/register")
    public String register(@Validated UserRegisterVo userRegisterVo, BindingResult result, RedirectAttributes redirectAttributes) {
        //UserRegisterVo中有属性校验出错，重新转发到注册页面
        if (result.hasErrors()) {
            //将校验错误信息存入Map，再放入Model页面中
            Map<String, String> errorMap = result.getFieldErrors().stream().collect(
                    Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage)
            );
            redirectAttributes.addFlashAttribute("errors", errorMap);
            return "redirect:http://auth.gulimall.com/reg.html";
        }
        //UserRegisterVo中所有属性通过了JSR303校验，先比对验证码是否正确，再执行注册逻辑
        String code = userRegisterVo.getCode();
        String redisCode = redisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + userRegisterVo.getMobile());
        if (!StringUtils.isEmpty(redisCode)) {
            //用户输入的验证码与Redis中保存的验证码相同
            if (code.equals(redisCode.split("_")[0])) {
                //删除验证码，令牌机制
                redisTemplate.delete(AuthServerConstant.SMS_CODE_CACHE_PREFIX + userRegisterVo.getMobile());
                //真正进行注册，远程调用member服务
                R res = memberFeignService.register(userRegisterVo);
                if (res.getCode() == 0) {
                    //远程调用成功，注册完成，跳转至登录页面
                    return "redirect:http://auth.gulimall.com/login.html";
                } else {
                    Map<String, String> errorMap = new HashMap<>();
                    errorMap.put("errorMsg", res.getData("msg", new TypeReference<String>(){}));
                    redirectAttributes.addFlashAttribute("errors", errorMap);
                    return "redirect:http://auth.gulimall.com/reg.html";
                }
            } else { //用户输入的验证码与Redis中保存的验证码不相同
                Map<String, String> errorMap = new HashMap<>();
                errorMap.put("code", "验证码错误");
                redirectAttributes.addFlashAttribute("errors", errorMap);
                return "redirect:http://auth.gulimall.com/reg.html";
            }
        } else {
            Map<String, String> errorMap = new HashMap<>();
            errorMap.put("code", "验证码错误");
            redirectAttributes.addFlashAttribute("errors", errorMap);
            return "redirect:http://auth.gulimall.com/reg.html";
        }
    }

    /**
     * 用户登录
     */
    @PostMapping(value = "/login")
    public String login(@Validated UserLoginVo userLoginVo,
                        RedirectAttributes redirectAttributes,
                        HttpSession session) {
        R result = memberFeignService.login(userLoginVo);
        if (result.getCode() == 0) {
            MemberResponseVo member = result.getData("data", new TypeReference<MemberResponseVo>(){});
            //登录成功之后，将用户信息member放到session中，再跳转回首页
            session.setAttribute(AuthServerConstant.SESSION_KEY, member);
            return "redirect:http://gulimall.com";
        } else {
            Map<String, String> errorMap = new HashMap<>();
            errorMap.put("errorMsg", result.getData("key", new TypeReference<String>(){}));
            redirectAttributes.addFlashAttribute("errors", errorMap);
            return "redirect:http://auth.gulimall.com/login.html";
        }
    }

    /**
     * 如果用户登录过了，再访问登录页的地址，就直接跳转到商城首页；如果没登录，跳转到登录页正常登录
     */
    @GetMapping(value = "/login.html")
    public String loginPage(HttpSession session) {
        //尝试从session中获取用户登录时保存的数据
        Object attribute = session.getAttribute(AuthServerConstant.SESSION_KEY);
        if (Objects.isNull(attribute)) { //没获取到，则说明没登录，跳转到登录页
            return "login";
        } else { //获取到，则说明用户已登录，跳转到商城首页
            return "redirect:http://gulimall.com";
        }
    }
}
